#include "vns.h"
#include <limits.h>

#define DEBUG(x) if(x)
#define TRAZA 0
#define PARADA 0
#define MEJORA 0
#define INTERCAMBIA 0

   
   
   /**
    * Constructor por defecto
    * */
    VNS::VNS(){}
       
   /** 
    * Constructor
    * @param listado de los rectángulos a empaquetar
    * */    
   VNS::VNS(list<Rectangulo> lista): Heuristica (lista) {
      DEBUG(TRAZA) cout << "VNS::Constructor(listado) con lista de tamaño= " << lista.size() << endl;
      kMax = (int)candidatos.size()/2; //La máxima k no puede ser mayor a la mitad de los rectangulos 
      k = 0;
    }
    
   bool VNS::parada(int valor) {
      DEBUG(TRAZA) cout << "VNS::parada("<<valor<< "), iteracion: " << iteracion << endl;       
      iteracion++;
      if (k == kMax) {
         k = 0; //Empezamos en un nuevo espacio de búsqueda
      } else {
         k++;
      }
      if (valor < mejorSol) {
         mejorSol = valor;
         mejor = solucion;
         iteracionSinCambio = 0;
         k = 0;
      } else {
         iteracionSinCambio++;
      }

      if (iteracion == MAX_ITERACIONES) {
         cout << "Alcanzado máximo de iteraciones: " << MAX_ITERACIONES  << endl;
         return true;
      }
      if (iteracionSinCambio == MAX_ITERACIONES_SIN_CAMBIO) {
         cout << "Alcanzado máximo de iteraciones sin mejora: " << MAX_ITERACIONES_SIN_CAMBIO << endl;
         return true;
      }
      return false;
   }
   
      /**
       * Mejorar Solución modificando el espacio de búsqueda en base al parametro k
       *    La idea es intercambiar los k últimos rectangulos por 
       *    los k siguientes de la solución actual. Se rotan los del primer grupo
       * */
      list<Rectangulo> VNS::mejoraSolucion() {
         DEBUG(TRAZA) cout << endl << "VNS::mejoraSolucion() k: " << k << " de " << kMax <<
                                     ". Iteracion: " << iteracion << 
                                     "  Iteración sin mejora: " << iteracionSinCambio << endl;
         list<Rectangulo>::reverse_iterator it = solucion.rend();
         //iteracion++;
         
         if (k == 0) { //Cambiar espacio de búsqueda
            DEBUG(MEJORA) cout << "k == 0! : continuamos buscando con k pero con la mejor solucion" << endl;
         }
         intercambia(k);
  
         return solucion;
      }
      
      
      list <Rectangulo> VNS::intercambia(int k) {
         DEBUG(TRAZA) cout << endl << "VNS::intercambia k: " << k << " de " << kMax << endl;
         list <Rectangulo> a;
         list <Rectangulo> b;
         list <Rectangulo>::iterator it;
         DEBUG(INTERCAMBIA) cout << "ANTES DEL INTERCAMBIO" << endl;
         for (it = solucion.begin(); it != solucion.end(); it++)
            DEBUG(INTERCAMBIA)    cout << "Rectangulo: " << it->getid() << endl;
         for (int i = 0; i < k; i++) { //Sacamos el primer bloque
            it = solucion.end();
            it--;
            a.push_back(*it);
            solucion.pop_back();
         }
         for (int i = 0; i < k; i++) { //Sacamos el segundo bloque
            it = solucion.end();
            it--;
            b.push_back(*it);
            solucion.pop_back();
         }
         a.reverse(); //Le damos la vuelta para volver a meterlo correctamente
         for (it = a.begin(); it != a.end(); it++) { //Metemos el primer bloque
            DEBUG(INTERCAMBIA) cout << "Primer Bloque: " << it->getid() << endl;
            it->rotar(); //Además lo rotamos
            solucion.push_back(*it);
         }
         b.reverse(); //Le damos la vuelta para volver a meterlo correctamente
         for (it = b.begin(); it != b.end(); it++) { //Metemos el segundo bloque
            DEBUG(INTERCAMBIA)  cout << "Segundo bloque: " << it->getid() << endl;
            //it->rotar(); //Además lo rotamos
            solucion.push_back(*it);
         }
         //TEST
         DEBUG(INTERCAMBIA) cout << "DESPUES DEL INTERCAMBIO" << endl;
         for (it = solucion.begin(); it != solucion.end(); it++)
            DEBUG(INTERCAMBIA) cout << "Rectangulo: " << it->getid() << endl;
         return solucion;   
      }
